home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Game Programming Gurus / Tricks of the Windows Game Programming Gurus (SAMS)(2000).iso / Goodies / t3dlib3.cpp < prev    next >
C/C++ Source or Header  |  1999-08-30  |  23KB  |  887 lines

  1. // T3DLIB3.CPP - Game Engine Part III, sound & music
  2.  
  3. // INCLUDES ///////////////////////////////////////////////
  4.  
  5. #define WIN32_LEAN_AND_MEAN  
  6.  
  7. #include <windows.h>   // include important windows stuff
  8. #include <windowsx.h> 
  9. #include <mmsystem.h>
  10. #include <objbase.h>
  11. #include <iostream.h> // include important C/C++ stuff
  12. #include <conio.h>
  13. #include <stdlib.h>
  14. #include <malloc.h>
  15. #include <memory.h>
  16. #include <string.h>
  17. #include <stdarg.h>
  18. #include <stdio.h>
  19. #include <math.h>
  20. #include <io.h>
  21. #include <fcntl.h>
  22. #include <direct.h>
  23. #include <wchar.h>
  24.  
  25. #include <ddraw.h>  // directX includes
  26. #include <dsound.h>
  27. #include <dmksctrl.h>
  28. #include <dmusici.h>
  29. #include <dmusicc.h>
  30. #include <dmusicf.h>
  31.  
  32.  
  33. #include "T3DLIB3.H"
  34.  
  35. // DEFINES ////////////////////////////////////////////////
  36.  
  37. // TYPES //////////////////////////////////////////////////
  38.  
  39. // PROTOTYPES /////////////////////////////////////////////
  40.  
  41. // EXTERNALS /////////////////////////////////////////////
  42.  
  43. extern HWND main_window_handle;     // access to main window handle in main module
  44.  
  45. // GLOBALS ////////////////////////////////////////////////
  46.  
  47. // directsound stuff
  48. LPDIRECTSOUND        lpds = NULL;    // directsound interface pointer
  49. DSBUFFERDESC        dsbd;           // directsound description
  50. DSCAPS                dscaps;         // directsound caps
  51. HRESULT                dsresult;       // general directsound result
  52. DSBCAPS                dsbcaps;        // directsound buffer caps
  53. LPDIRECTSOUNDBUFFER    lpdsbprimary = NULL;   // the primary mixing buffer
  54. pcm_sound            sound_fx[MAX_SOUNDS];    // the array of secondary sound buffers
  55.  
  56. WAVEFORMATEX        pcmwf;          // generic waveformat structure
  57.  
  58. // direct music globals
  59. IDirectMusicPerformance    *dm_perf = NULL;    // the directmusic performance manager 
  60. IDirectMusicLoader         *dm_loader = NULL;  // the directmusic loader
  61.  
  62. // this hold all the directmusic midi objects
  63. DMUSIC_MIDI                dm_midi[DM_NUM_SEGMENTS];
  64. int dm_active_id = -1;     // currently active midi segment
  65.  
  66. // FUNCTIONS //////////////////////////////////////////////
  67.  
  68. int DSound_Load_WAV(char *filename, int control_flags)
  69. {
  70. // this function loads a .wav file, sets up the directsound 
  71. // buffer and loads the data into memory, the function returns 
  72. // the id number of the sound
  73.  
  74.  
  75. HMMIO             hwav;    // handle to wave file
  76. MMCKINFO        parent,  // parent chunk
  77.                 child;   // child chunk
  78. WAVEFORMATEX    wfmtx;   // wave format structure
  79.  
  80. int    sound_id = -1,       // id of sound to be loaded
  81.     index;               // looping variable
  82.  
  83. UCHAR *snd_buffer,       // temporary sound buffer to hold voc data
  84.       *audio_ptr_1=NULL, // data ptr to first write buffer 
  85.       *audio_ptr_2=NULL; // data ptr to second write buffer
  86.  
  87. DWORD audio_length_1=0,  // length of first write buffer
  88.       audio_length_2=0;  // length of second write buffer
  89.             
  90. // step one: are there any open id's ?
  91. for (index=0; index < MAX_SOUNDS; index++)
  92.     {    
  93.     // make sure this sound is unused
  94.     if (sound_fx[index].state==SOUND_NULL)
  95.        {
  96.        sound_id = index;
  97.        break;
  98.        } // end if
  99.  
  100.     } // end for index
  101.  
  102. // did we get a free id?
  103. if (sound_id==-1)
  104.     return(-1);
  105.  
  106. // set up chunk info structure
  107. parent.ckid         = (FOURCC)0;
  108. parent.cksize         = 0;
  109. parent.fccType        = (FOURCC)0;
  110. parent.dwDataOffset = 0;
  111. parent.dwFlags        = 0;
  112.  
  113. // copy data
  114. child = parent;
  115.  
  116. // open the WAV file
  117. if ((hwav = mmioOpen(filename, NULL, MMIO_READ | MMIO_ALLOCBUF))==NULL)
  118.     return(-1);
  119.  
  120. // descend into the RIFF 
  121. parent.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  122.  
  123. if (mmioDescend(hwav, &parent, NULL, MMIO_FINDRIFF))
  124.     {
  125.     // close the file
  126.     mmioClose(hwav, 0);
  127.  
  128.     // return error, no wave section
  129.     return(-1);     
  130.     } // end if
  131.  
  132. // descend to the WAVEfmt 
  133. child.ckid = mmioFOURCC('f', 'm', 't', ' ');
  134.  
  135. if (mmioDescend(hwav, &child, &parent, 0))
  136.     {
  137.     // close the file
  138.     mmioClose(hwav, 0);
  139.  
  140.     // return error, no format section
  141.     return(-1);     
  142.     } // end if
  143.  
  144. // now read the wave format information from file
  145. if (mmioRead(hwav, (char *)&wfmtx, sizeof(wfmtx)) != sizeof(wfmtx))
  146.     {
  147.     // close file
  148.     mmioClose(hwav, 0);
  149.  
  150.     // return error, no wave format data
  151.     return(-1);
  152.     } // end if
  153.  
  154. // make sure that the data format is PCM
  155. if (wfmtx.wFormatTag != WAVE_FORMAT_PCM)
  156.     {
  157.     // close the file
  158.     mmioClose(hwav, 0);
  159.  
  160.     // return error, not the right data format
  161.     return(-1); 
  162.     } // end if
  163.  
  164. // now ascend up one level, so we can access data chunk
  165. if (mmioAscend(hwav, &child, 0))
  166.    {
  167.    // close file
  168.    mmioClose(hwav, 0);
  169.  
  170.    // return error, couldn't ascend
  171.    return(-1);     
  172.    } // end if
  173.  
  174. // descend to the data chunk 
  175. child.ckid = mmioFOURCC('d', 'a', 't', 'a');
  176.  
  177. if (mmioDescend(hwav, &child, &parent, MMIO_FINDCHUNK))
  178.     {
  179.     // close file
  180.     mmioClose(hwav, 0);
  181.  
  182.     // return error, no data
  183.     return(-1);     
  184.     } // end if
  185.  
  186. // finally!!!! now all we have to do is read the data in and
  187. // set up the directsound buffer
  188.  
  189. // allocate the memory to load sound data
  190. snd_buffer = (UCHAR *)malloc(child.cksize);
  191.  
  192. // read the wave data 
  193. mmioRead(hwav, (char *)snd_buffer, child.cksize);
  194.  
  195. // close the file
  196. mmioClose(hwav, 0);
  197.  
  198. // set rate and size in data structure
  199. sound_fx[sound_id].rate  = wfmtx.nSamplesPerSec;
  200. sound_fx[sound_id].size  = child.cksize;
  201. sound_fx[sound_id].state = SOUND_LOADED;
  202.  
  203. // set up the format data structure
  204. memset(&pcmwf, 0, sizeof(WAVEFORMATEX));
  205.  
  206. pcmwf.wFormatTag      = WAVE_FORMAT_PCM;  // pulse code modulation
  207. pcmwf.nChannels          = 1;                // mono 
  208. pcmwf.nSamplesPerSec  = 11025;            // always this rate
  209. pcmwf.nBlockAlign      = 1;                
  210. pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign;
  211. pcmwf.wBitsPerSample  = 8;
  212. pcmwf.cbSize          = 0;
  213.  
  214. // prepare to create sounds buffer
  215. dsbd.dwSize            = sizeof(DSBUFFERDESC);
  216. dsbd.dwFlags        = control_flags | DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE;
  217. dsbd.dwBufferBytes    = child.cksize;
  218. dsbd.lpwfxFormat    = &pcmwf;
  219.  
  220. // create the sound buffer
  221. if (FAILED(lpds->CreateSoundBuffer(&dsbd,&sound_fx[sound_id].dsbuffer,NULL)))
  222.    {
  223.    // release memory
  224.    free(snd_buffer);
  225.  
  226.    // return error
  227.    return(-1);
  228.    } // end if
  229.  
  230. // copy data into sound buffer
  231. if (FAILED(sound_fx[sound_id].dsbuffer->Lock(0,                     
  232.                                       child.cksize,            
  233.                                       (void **) &audio_ptr_1, 
  234.                                       &audio_length_1,
  235.                                       (void **)&audio_ptr_2, 
  236.                                       &audio_length_2,
  237.                                       DSBLOCK_FROMWRITECURSOR)))
  238.                                  return(0);
  239.  
  240. // copy first section of circular buffer
  241. memcpy(audio_ptr_1, snd_buffer, audio_length_1);
  242.  
  243. // copy last section of circular buffer
  244. memcpy(audio_ptr_2, (snd_buffer+audio_length_1),audio_length_2);
  245.  
  246. // unlock the buffer
  247. if (FAILED(sound_fx[sound_id].dsbuffer->Unlock(audio_ptr_1, 
  248.                                         audio_length_1, 
  249.                                         audio_ptr_2, 
  250.                                         audio_length_2)))
  251.                                   return(0);
  252.  
  253. // release the temp buffer
  254. free(snd_buffer);
  255.  
  256. // return id
  257. return(sound_id);
  258.  
  259. } // end DSound_Load_WAV
  260.  
  261. ///////////////////////////////////////////////////////////
  262.  
  263. int DSound_Replicate_Sound(int source_id)
  264. {
  265. // this function replicates the sent sound and sends back the
  266. // id of the replicated sound, you would use this function
  267. // to make multiple copies of a gunshot or something that
  268. // you want to play multiple times simulataneously, but you
  269. // only want to load once
  270.  
  271. if (source_id!=-1)
  272.     {
  273.     // duplicate the sound buffer
  274.     // first hunt for an open id
  275.  
  276.     for (int id=0; id < MAX_SOUNDS; id++)
  277.         {
  278.         // is this sound open?
  279.         if (sound_fx[id].state==SOUND_NULL)
  280.             {
  281.             // first make an identical copy
  282.             sound_fx[id] = sound_fx[source_id];
  283.  
  284.             // now actually replicate the directsound buffer
  285.             if (FAILED(lpds->DuplicateSoundBuffer(sound_fx[source_id].dsbuffer,
  286.                                            &sound_fx[id].dsbuffer)))
  287.                 {
  288.                 // reset sound to NULL
  289.                 sound_fx[id].dsbuffer = NULL;
  290.                 sound_fx[id].state    = SOUND_NULL;
  291.  
  292.                 // return error
  293.                 return(-1);
  294.                 } // end if
  295.  
  296.             // now fix up id
  297.             sound_fx[id].id = id;
  298.             
  299.             // return replicated sound
  300.             return(id);
  301.  
  302.             } // end if found
  303.   
  304.         } // end for id
  305.  
  306.     } // end if
  307. else
  308.    return(-1);
  309.     
  310. // else failure
  311. return(-1);
  312.  
  313. } // end DSound_Replicate_Sound
  314.  
  315. //////////////////////////////////////////////////////////
  316.  
  317. int DSound_Init(void)
  318. {
  319. // this function initializes the sound system
  320. static int first_time = 1; // used to track the first time the function
  321.                            // is entered
  322.  
  323. // test for very first time
  324. if (first_time)
  325.     {        
  326.     // clear everything out
  327.     memset(sound_fx,0,sizeof(pcm_sound)*MAX_SOUNDS);
  328.     
  329.     // reset first time
  330.     first_time = 0;
  331.  
  332.     // create a directsound object
  333.     if (FAILED(DirectSoundCreate(NULL, &lpds, NULL)))
  334.         return(0);
  335.  
  336.     // set cooperation level
  337.     if (FAILED(lpds->SetCooperativeLevel((HWND)main_window_handle,DSSCL_NORMAL)))
  338.         return(0);
  339.  
  340.     } // end if
  341.  
  342. // initialize the sound fx array
  343. for (int index=0; index<MAX_SOUNDS; index++)
  344.     {
  345.     // test if this sound has been loaded
  346.     if (sound_fx[index].dsbuffer)
  347.         {
  348.         // stop the sound
  349.         sound_fx[index].dsbuffer->Stop();
  350.  
  351.         // release the buffer
  352.         sound_fx[index].dsbuffer->Release();
  353.     
  354.         } // end if
  355.  
  356.     // clear the record out
  357.     memset(&sound_fx[index],0,sizeof(pcm_sound));
  358.  
  359.     // now set up the fields
  360.     sound_fx[index].state = SOUND_NULL;
  361.     sound_fx[index].id    = index;
  362.  
  363.     } // end for index
  364.  
  365. // return sucess
  366. return(1);
  367.  
  368. } // end DSound_Init
  369.  
  370. ///////////////////////////////////////////////////////////
  371.  
  372. int DSound_Shutdown(void)
  373. {
  374. // this function releases all the memory allocated and the directsound object
  375. // itself
  376.  
  377. // first turn all sounds off
  378. DSound_Stop_All_Sounds();
  379.  
  380. // now release all sound buffers
  381. for (int index=0; index<MAX_SOUNDS; index++)
  382.     if (sound_fx[index].dsbuffer)
  383.         sound_fx[index].dsbuffer->Release();
  384.  
  385. // now release the directsound interface itself
  386. if (lpds)
  387.    lpds->Release();
  388.  
  389. // return success
  390. return(1);
  391.  
  392. } // end DSound_Shutdown
  393.  
  394. ///////////////////////////////////////////////////////////
  395.  
  396. int DSound_Play(int id, int flags, int volume, int rate, int pan)
  397. {
  398. // this function plays a sound, the only parameter that 
  399. // works is the flags which can be 0 to play once or
  400. // DSBPLAY_LOOPING
  401.  
  402. if (sound_fx[id].dsbuffer)
  403.     {
  404.     // reset position to start
  405.     if (FAILED(sound_fx[id].dsbuffer->SetCurrentPosition(0)))
  406.         return(0);
  407.     
  408.     // play sound
  409.     if (FAILED(sound_fx[id].dsbuffer->Play(0,0,flags)))
  410.         return(0);
  411.     } // end if
  412.  
  413. // return success
  414. return(1);
  415.  
  416. } // end DSound_Play
  417.  
  418. ///////////////////////////////////////////////////////////
  419.  
  420. int DSound_Set_Volume(int id,int vol)
  421. {
  422. // this function sets the volume on a sound 0-100
  423.  
  424. if (sound_fx[id].dsbuffer->SetVolume(DSVOLUME_TO_DB(vol))!=DS_OK)
  425.     return(0);
  426.  
  427. // return success
  428. return(1);
  429.  
  430. } // end DSound_Set_Volume
  431.  
  432. ///////////////////////////////////////////////////////////
  433.  
  434. int DSound_Set_Freq(int id,int freq)
  435. {
  436. // this function sets the playback rate
  437.  
  438. if (sound_fx[id].dsbuffer->SetFrequency(freq)!=DS_OK)
  439.     return(0);
  440.  
  441. // return success
  442. return(1);
  443.  
  444. } // end DSound_Set_Freq
  445.  
  446. ///////////////////////////////////////////////////////////
  447.  
  448. int DSound_Set_Pan(int id,int pan)
  449. {
  450. // this function sets the pan, -10,000 to 10,0000
  451.  
  452. if (sound_fx[id].dsbuffer->SetPan(pan)!=DS_OK)
  453.     return(0);
  454.  
  455. // return success
  456. return(1);
  457.  
  458. } // end DSound_Set_Pan
  459.  
  460. ////////////////////////////////////////////////////////////
  461.  
  462. int DSound_Stop_Sound(int id)
  463. {
  464. // this function stops a sound from playing
  465. if (sound_fx[id].dsbuffer)
  466.    {
  467.    sound_fx[id].dsbuffer->Stop();
  468.    sound_fx[id].dsbuffer->SetCurrentPosition(0);
  469.    } // end if
  470.  
  471. // return success
  472. return(1);
  473.  
  474. } // end DSound_Stop_Sound
  475.  
  476. ///////////////////////////////////////////////////////////
  477.  
  478. int DSound_Delete_All_Sounds(void)
  479. {
  480. // this function deletes all the sounds
  481.  
  482. for (int index=0; index < MAX_SOUNDS; index++)
  483.     DSound_Delete_Sound(index);
  484.  
  485. // return success always
  486. return(1);
  487.  
  488. } // end DSound_Delete_All_Sounds
  489.  
  490. ///////////////////////////////////////////////////////////
  491.  
  492. int DSound_Delete_Sound(int id)
  493. {
  494. // this function deletes a single sound and puts it back onto the available list
  495.  
  496. // first stop it
  497. if (!DSound_Stop_Sound(id))
  498.    return(0);
  499.  
  500. // now delete it
  501. if (sound_fx[id].dsbuffer)
  502.    {
  503.    // release the com object
  504.    sound_fx[id].dsbuffer->Release();
  505.    sound_fx[id].dsbuffer = NULL;
  506.    
  507.    // return success
  508.    return(1);
  509.    } // end if
  510.  
  511. // return success
  512. return(1);
  513.  
  514. } // end DSound_Delete_Sound
  515.  
  516. ///////////////////////////////////////////////////////////
  517.  
  518. int DSound_Stop_All_Sounds(void)
  519. {
  520. // this function stops all sounds
  521.  
  522. for (int index=0; index<MAX_SOUNDS; index++)
  523.     DSound_Stop_Sound(index);    
  524.  
  525. // return success
  526. return(1);
  527.  
  528. } // end DSound_Stop_All_Sounds
  529.  
  530. ///////////////////////////////////////////////////////////
  531.  
  532. int DSound_Status_Sound(int id)
  533. {
  534. // this function returns the status of a sound
  535. if (sound_fx[id].dsbuffer)
  536.     {
  537.     ULONG status; 
  538.  
  539.     // get the status
  540.     sound_fx[id].dsbuffer->GetStatus(&status);
  541.  
  542.     // return the status
  543.     return(status);
  544.  
  545.     } // end if
  546. else // total failure
  547.     return(-1);
  548.  
  549. } // end DSound_Status_Sound
  550.  
  551. ///////////////////////////////////////////////////////////
  552.  
  553. int DMusic_Load_MIDI(char *filename)
  554. {
  555. // this function loads a midi segment
  556.  
  557. DMUS_OBJECTDESC ObjDesc; 
  558. HRESULT hr;
  559. IDirectMusicSegment* pSegment = NULL;
  560.  
  561. int index; // loop var
  562.  
  563. // look for open slot for midi segment
  564. int id = -1;
  565.  
  566. for (index = 0; index < DM_NUM_SEGMENTS; index++)
  567.     {
  568.     // is this one open
  569.     if (dm_midi[index].state == MIDI_NULL)
  570.        {
  571.        // validate id, but don't validate object until loaded
  572.        id = index;
  573.        break;
  574.        } // end if
  575.  
  576.     } // end for index
  577.  
  578. // found good id?
  579. if (id==-1)
  580.    return(-1);
  581.  
  582. // get current working directory
  583. char szDir[_MAX_PATH];
  584. WCHAR wszDir[_MAX_PATH]; 
  585.  
  586. if(_getcwd( szDir, _MAX_PATH ) == NULL)
  587.   {
  588.   return(-1);;
  589.   } // end if
  590.  
  591. MULTI_TO_WIDE(wszDir, szDir);
  592.  
  593. // tell the loader were to look for files
  594. hr = dm_loader->SetSearchDirectory(GUID_DirectMusicAllTypes,wszDir, FALSE);
  595.  
  596. if (FAILED(hr)) 
  597.    {
  598.    return (-1);
  599.    } // end if
  600.  
  601. // convert filename to wide string
  602. WCHAR wfilename[_MAX_PATH]; 
  603. MULTI_TO_WIDE(wfilename, filename);
  604.  
  605. // setup object description
  606. DD_INIT_STRUCT(ObjDesc);
  607. ObjDesc.guidClass = CLSID_DirectMusicSegment;
  608. wcscpy(ObjDesc.wszFileName, wfilename );
  609. ObjDesc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;
  610.  
  611. // load the object and query it for the IDirectMusicSegment interface
  612. // This is done in a single call to IDirectMusicLoader::GetObject
  613. // note that loading the object also initializes the tracks and does 
  614. // everything else necessary to get the MIDI data ready for playback.
  615.  
  616. hr = dm_loader->GetObject(&ObjDesc,IID_IDirectMusicSegment, (void**) &pSegment);
  617.  
  618. if (FAILED(hr))
  619.    return(-1);
  620.  
  621. // ensure that the segment plays as a standard MIDI file
  622. // you now need to set a parameter on the band track
  623. // Use the IDirectMusicSegment::SetParam method and let 
  624. // DirectMusic find the trackby passing -1 (or 0xFFFFFFFF) in the dwGroupBits method parameter.
  625.  
  626. hr = pSegment->SetParam(GUID_StandardMIDIFile,-1, 0, 0, (void*)dm_perf);
  627.  
  628. if (FAILED(hr))
  629.    return(-1);
  630.   
  631. // This step is necessary because DirectMusic handles program changes and 
  632. // bank selects differently for standard MIDI files than it does for MIDI 
  633. // content authored specifically for DirectMusic. 
  634. // The GUID_StandardMIDIFile parameter must be set before the instruments are downloaded. 
  635.  
  636. // The next step is to download the instruments. 
  637. // This is necessary even for playing a simple MIDI file 
  638. // because the default software synthesizer needs the DLS data 
  639. // for the General MIDI instrument set
  640. // If you skip this step, the MIDI file will play silently.
  641. // Again, you call SetParam on the segment, this time specifying the GUID_Download parameter:
  642.  
  643. hr = pSegment->SetParam(GUID_Download, -1, 0, 0, (void*)dm_perf);
  644.  
  645. if (FAILED(hr))
  646.    return(-1);
  647.  
  648. // at this point we have MIDI loaded and a valid object
  649.  
  650. dm_midi[id].dm_segment  = pSegment;
  651. dm_midi[id].dm_segstate = NULL;
  652. dm_midi[id].state       = MIDI_LOADED;
  653.  
  654. // return id
  655. return(id);
  656.  
  657. } // end DMusic_Load_MIDI
  658.  
  659. //////////////////////////////////////////////////////////
  660.  
  661. int DMusic_Play(int id)
  662. {
  663. // play sound based on id
  664.  
  665. if (dm_midi[id].dm_segment && dm_midi[id].state!=MIDI_NULL)
  666.    {
  667.    // if there is an active midi then stop it
  668.    if (dm_active_id!=-1)
  669.        DMusic_Stop(dm_active_id);
  670.  
  671.    // play segment and force tracking of state variable
  672.    dm_perf->PlaySegment(dm_midi[id].dm_segment, 0, 0, &dm_midi[id].dm_segstate);
  673.    dm_midi[id].state = MIDI_PLAYING;
  674.  
  675.    // set the active midi segment
  676.    dm_active_id = id;
  677.    return(1);
  678.    }  // end if
  679. else
  680.     return(0);
  681.  
  682. } // end DMusic_Play
  683.  
  684. //////////////////////////////////////////////////////////
  685.  
  686. int DMusic_Stop(int id)
  687. {
  688. // stop a midi segment
  689. if (dm_midi[id].dm_segment && dm_midi[id].state!=MIDI_NULL)
  690.    {
  691.    // play segment and force tracking of state variable
  692.    dm_perf->Stop(dm_midi[id].dm_segment, NULL, 0, 0);
  693.    dm_midi[id].state = MIDI_STOPPED;
  694.  
  695.    // reset active id
  696.    dm_active_id = -1;
  697.  
  698.    return(1);
  699.    }  // end if
  700. else
  701.     return(0);
  702.  
  703. } // end DMusic_Stop
  704.  
  705. ///////////////////////////////////////////////////////////
  706.  
  707. int DMusic_Delete_MIDI(int id)
  708. {
  709. // this function deletes one MIDI segment
  710.  
  711. // Unload instruments this will cause silence.
  712. // CloseDown unloads all instruments, so this call is also not 
  713. // strictly necessary.
  714. if (dm_midi[id].dm_segment)
  715.    {
  716.    dm_midi[id].dm_segment->SetParam(GUID_Unload, -1, 0, 0, (void*)dm_perf); 
  717.  
  718.    // Release the segment and set to null
  719.    dm_midi[id].dm_segment->Release(); 
  720.    dm_midi[id].dm_segment  = NULL;
  721.    dm_midi[id].dm_segstate = NULL;
  722.    dm_midi[id].state       = MIDI_NULL;
  723.    } // end if
  724.  
  725. return(1);
  726.  
  727. } // end DMusic_Delete_MIDI
  728.  
  729. //////////////////////////////////////////////////////////
  730.  
  731. int DMusic_Delete_All_MIDI(void)
  732. {
  733. // delete all the MIDI 
  734. int index; // loop var
  735.  
  736. // free up all the segments
  737. for (index = 0; index < DM_NUM_SEGMENTS; index++)
  738.     {
  739.     // Unload instruments this will cause silence.
  740.     // CloseDown unloads all instruments, so this call is also not 
  741.     // strictly necessary.
  742.     if (dm_midi[index].dm_segment)
  743.        {
  744.        dm_midi[index].dm_segment->SetParam(GUID_Unload, -1, 0, 0, (void*)dm_perf); 
  745.  
  746.        // Release the segment and set to null
  747.        dm_midi[index].dm_segment->Release(); 
  748.        dm_midi[index].dm_segment  = NULL;
  749.        dm_midi[index].dm_segstate = NULL;
  750.        dm_midi[index].state       = MIDI_NULL;
  751.        } // end if
  752.  
  753.     } // end for index
  754.  
  755. return(1);
  756.  
  757. } // end DMusic_Delete_All_MIDI
  758.  
  759. //////////////////////////////////////////////////////////
  760.  
  761. int DMusic_Status_MIDI(int id)
  762. {
  763. // this checks the status of a midi segment
  764.  
  765. if (dm_midi[id].dm_segment && dm_midi[id].state !=MIDI_NULL )
  766.    {
  767.    // get the status and translate to our defines
  768.    if (dm_perf->IsPlaying(dm_midi[id].dm_segment,NULL) == S_OK) 
  769.       dm_midi[id].state = MIDI_PLAYING;
  770.    else
  771.       dm_midi[id].state = MIDI_STOPPED;
  772.  
  773.    return(dm_midi[id].state);
  774.    } // end if
  775. else
  776.    return(0);
  777.  
  778. } // end DMusic_Status_MIDI
  779.  
  780. ///////////////////////////////////////////////////////////
  781.  
  782. int DMusic_Init(void)
  783. {
  784. // this function initializes directmusic, it also checks if directsound has
  785. // been initialized, if so it connect the wave output to directsound, otherwise
  786. // it creates it's own directsound object, hence you must start directsound up
  787. // first if you want to use both directsound and directmusic
  788.  
  789. int index; // looping var
  790.  
  791. // set up directmusic
  792. // initialize COM
  793. if (FAILED(CoInitialize(NULL)))
  794.    {    
  795.    // Terminate the application.
  796.    return(0);
  797.    }   // end if
  798.  
  799. // create the performance
  800. if (FAILED(CoCreateInstance(CLSID_DirectMusicPerformance,
  801.                             NULL,
  802.                             CLSCTX_INPROC,
  803.                             IID_IDirectMusicPerformance,
  804.                             (void**)&dm_perf)))    
  805.    {
  806.    // return null        
  807.    return(0);
  808.    } // end if
  809.  
  810. // initialize the performance, check if directsound is on-line if so, use the
  811. // directsound object, otherwise create a new one
  812. if (FAILED(dm_perf->Init(NULL, lpds, main_window_handle)))
  813.    {
  814.    return(0);// Failure -- performance not initialized
  815.    } // end if 
  816.  
  817. // add the port to the performance
  818. if (FAILED(dm_perf->AddPort(NULL)))
  819.    {    
  820.    return(0);// Failure -- port not initialized
  821.    } // end if
  822.  
  823. // create the loader to load object(s) such as midi file
  824. if (FAILED(CoCreateInstance(
  825.           CLSID_DirectMusicLoader,
  826.           NULL,
  827.           CLSCTX_INPROC, 
  828.           IID_IDirectMusicLoader,
  829.           (void**)&dm_loader)))
  830.    {
  831.    // error
  832.    return(0);
  833.    } // end if
  834.  
  835. // reset all the midi segment objects
  836. for (index = 0; index < DM_NUM_SEGMENTS; index++)
  837.     {
  838.     // reset the object
  839.     dm_midi[index].dm_segment  = NULL;  
  840.     dm_midi[index].dm_segstate = NULL;  
  841.     dm_midi[index].state       = MIDI_NULL;
  842.     dm_midi[index].id          = index;
  843.     } // end for index
  844.  
  845. // reset the active id
  846. dm_active_id = -1;
  847.  
  848. // all good baby
  849. return(1);
  850.  
  851. } // end DMusic_Init
  852.  
  853. ////////////////////////////////////////////////////////////
  854.  
  855. int DMusic_Shutdown(void)
  856. {
  857. int index;
  858.  
  859. // If there is any music playing, stop it. This is 
  860. // not really necessary, because the music will stop when
  861. // the instruments are unloaded or the performance is    
  862. // closed down.
  863. if (dm_perf)
  864.    dm_perf->Stop(NULL, NULL, 0, 0 ); 
  865.  
  866. // delete all the midis if they already haven't been
  867. DMusic_Delete_All_MIDI();
  868.  
  869. // CloseDown and Release the performance object.    
  870. if (dm_perf)
  871.    {
  872.    dm_perf->CloseDown();
  873.    dm_perf->Release();     
  874.    } // end if
  875.  
  876. // Release the loader object.
  877. if (dm_loader)
  878.    dm_loader->Release();     
  879.  
  880. // Release COM
  881. CoUninitialize(); 
  882.  
  883. // return success
  884. return(1);
  885.  
  886. } // end DMusic_Shutdown
  887.